#include "util.h"
#include "string_util.h"
#include "trace_def.h"
#include <cstdlib>
#include <iostream>
#include <fstream>
#include <vector>
#include <sstream>
#include <algorithm>
using namespace std;

static istream* input = &cin;
static ostream* output = &cout;

#ifdef __GNUC__
static void close_stream() {
#else
extern "C" static void close_stream() {
#endif
   if (input != &cin)
       delete input;
   if (output != &cout)
      delete output;
}

/* Read a line from the stream. A line can be continued by backslash.
 * Return false on EOF. */
static bool readline(istream& stream, string& s) {
    string line;
    s.erase();
    while ( getline(stream, line) ) { // newline is no included.
        int i = line.length() - 1;
        bool odd = false; // whether there's odd number of backslash at the end of line
        for (; i > 0 && line[i] == '\\'; --i)
            odd = !odd;
        if (odd) {
            line.erase(line.length() - 1, 1);
            s += line;
            continue;
        } else {
            s += line;
            return true;
        }
    }
    return false;
}

static ostringstream scriptfile;

class ProcLine {
private:
    ostream& stream;
public:
    ProcLine(ostream& s) : stream(s) {}
    void operator()(string line) {
        TraceItem item;
        string_trim(line);
        if (TraceItem::parse(line, item) != 0)
            cerr << "Warning! Error in input: " << line << endl;
        else
            stream << item << endl;;
    }
};

/**
 * Generate dtrace script for funcviz.
 * C++ is not the best language for the job. No here document,
 * no string split function, need to compile every time you
 * want to change the generated script ...
 * But the contest requires C/C++, so face it.
 */
int main(int argc, char** argv) {
    atexit(close_stream);

    scriptfile << "#!/usr/sbin/dtrace -s\n"
                  "#pragma D option quiet\n\n"
                  "dtrace:::BEGIN\n"
                  "{\n"
                  "    printf(\"Function Timestamp Module\\n\");\n"
                  "}\n\n";

    // Handle command line arguments.
    char* arg1 = NULL;
    char* arg2 = NULL;
    switch (argc) {
        case 2:
            arg1 = argv[1];
            break;
        case 3:
            arg1 = argv[1];
            arg2 = argv[2];
            break;
    }

    if (arg1 != NULL) {
        if (!file_exists(argv[1])) {
            err_sys("File dosen't exits");
            exit(1);
        }
        input = new ifstream(argv[1]);
    }

    if (arg2 != NULL)
        output = new ofstream(argv[2]);

    if (!input || !output) {
        err_sys("Can't open file");
        exit(1);
    }

    // Read input file and parse it.
    string line;
    vector<string> def;
    while (readline(*input, line)) {
        if (line.length() != 0)
            def.push_back(line);
    }

    for_each(def.begin(), def.end(), ProcLine(scriptfile));
    
    *output << scriptfile.str();
 
    return 0;
}

